#include <system.h>
#include <pio.h>
#include <std.h>
#include <error.h>

#define SYS_CLOCK_INTERRUPT 0
static unsigned long live=0;
static unsigned long timer_count=0;

static struct timer_call	{
	void (*entry)();
	unsigned long resolution;
	struct timer_call *next;
}*head;

static spin_lock tmr;

// *******************ADD protection salil

void timer()
{
	struct timer_call *temp;
	timer_count++;
	for(temp=head->next;temp!=NULL;temp=temp->next)	{
		if(timer_count%(temp->resolution)==NULL)	{
			(temp->entry)();
		}
	}
	live=0;
}

void add_timer_res(void *entry,unsigned long resolution)
{
	if(head==NULL)	{
		i_error("Timer ll not initialized");
	}
	struct timer_call *new;
	add_node_end(struct timer_call,head,new);
	new->entry=entry;
	new->resolution=resolution;
	new->next=NULL;
}

int add_timer(void *entry,int freq)
{
	unsigned long res;
	res=SYSTEM_SCHEDULE_CLOCK_SPEED/freq;
	add_timer_res(entry,res);
	printf("\nTimer request:%d:%x",freq,entry);
	return SUCCESS;
}

int modify_timer(void *entry_fn,int freq)
{
	struct timer_call *tmp;
	get_node(struct timer_call,head,entry,entry_fn,tmp);
	tmp->resolution=SYSTEM_SCHEDULE_CLOCK_SPEED/freq;
	printf("\nTimer request:%d:%x",freq,entry_fn);
	return SUCCESS;
}

int delete_timer(void *entry_fn)
{
	struct timer_call *temp;
	for(temp=head->next;(temp->entry)!=entry_fn && temp!=NULL;temp=temp->next);
	delete_node(struct timer_call,head,temp);
	printf("\nTimer delete:%x",entry_fn);
	return SUCCESS;
}

unsigned long proc_speed()
{
	unsigned long x,y,speed=0;
	int c;
	if((!interrupt_flag()) && is_irq(0))
		i_error("proc_speed:Unexpected irq state");
	live=1;
	while(live);
	live=1;
	x=SYSTEM_READ_TIMER();
	while(live);
	y=SYSTEM_READ_TIMER();
	speed=(y-x)/100;			//Cycles in usecond
	return speed/1000;
}


unsigned long cpuspeed2()
{
	unsigned long stsc,etsc,ticks,speed;
	unsigned char hi,lo;
	int i;
	outb(0x43,0x34);   // set PIT channel 0 to single-shot mode
	outb(0x40,0);
	outb(0x40,0);      // program the counter will be 0x10000 - n after n ticks
	stsc=SYSTEM_READ_TIMER();
	for (i=0x1000;i>0;i--);
	etsc=SYSTEM_READ_TIMER();
	outb(0x43,0x04);   // read PIT counter command ??
	lo=inb(0x40);
	hi=inb(0x40);
	ticks=(0x10000 - (hi*256+lo));
	speed=(etsc-stsc)*1193180 / ticks;
	setclock(SYSTEM_SCHEDULE_CLOCK_SPEED);
	return (speed/1000);
}

unsigned int read_timer()
{
	unsigned int val=0;
	outb(0x43,0x00);
	val|=(unsigned char)inb(0x40);
	val|=(((unsigned char)inb(0x40))<<8);
	return val;
}

unsigned long pspd=0;


void udelay(unsigned long count)
{
	unsigned long x,y;
	while(--count>0)	{
		x=SYSTEM_READ_TIMER();
		y=x;
		while((y-x)<=pspd)	{
			y=SYSTEM_READ_TIMER();
		}
	}
}

void mdelay(unsigned long count)
{
	unsigned long cnt,x,y;
	while(--count>0)	{
		cnt=1000;
		while(--cnt>0)	{
			x=SYSTEM_READ_TIMER();
			y=x;
			while((y-x)<=pspd)	{
				y=SYSTEM_READ_TIMER();
			}
		}
	}
}

void salil_is_alive()
{
	static int i=1;
	unsigned char *k=(unsigned char *)0xb809e;
	switch(i)	{
		case 1: *k=0x5c;
		i=2;
		break;
		case 2: *k='|';
		i=3;
		break;
		case 3: *k='/';
		i=4;
		break;
		case 4: *k='-';
		i=1;    
		break;
	}
}

void init_timer()
{
	int x;
	printf("\nStarting timer chain,Vffc"); 
	request_irq(0,timer);
	create_head(struct timer_call,head);
	head->next=NULL;
	head->entry=NULL;
	head->resolution=NULL;
	enable_irq(0);
	pspd=proc_speed();
	add_timer(salil_is_alive,3);
}
